//include "json-ast-token.h"

class AstBuildingParserJsonML : public AstBuildingParser {
 public:
  AstBuildingParserJsonML(Handle<Script> script, bool allow_natives_syntax,
                          v8::Extension* extension, ScriptDataImpl* pre_data)
      : AstBuildingParser(script, allow_natives_syntax, extension, NULL)  { }

  FunctionLiteral* ParseProgram(Handle<String> source,
                                      unibrow::CharacterStream* stream,
                                      bool in_global_context);
 
 protected:
  // --- ParserXXX function - from class Parser
  
  void* ParseSourceElements(ZoneListWrapper<Statement>* processor,
                            int end_token, bool* ok);
  
  // Statments - commented out implemented directly in switch. TODO - implement functions - probably cleaner                          
  Statement* ParseStatement(ZoneStringList* labels, bool* ok);
  //Statement* ParseFunctionDeclaration(bool* ok);
  //Statement* ParseNativeDeclaration(bool* ok);
  //Block* ParseBlock(ZoneStringList* labels, bool* ok);
  //Block* ParseVariableStatement(bool* ok);
  //Block* ParseVariableDeclarations(bool accept_IN, Expression** var, bool* ok);
  //Statement* ParseExpressionOrLabelledStatement(ZoneStringList* labels,
  //                                              bool* ok);
  //IfStatement* ParseIfStatement(ZoneStringList* labels, bool* ok);
  //Statement* ParseContinueStatement(bool* ok);
  //Statement* ParseBreakStatement(ZoneStringList* labels, bool* ok);
  //Statement* ParseReturnStatement(bool* ok);
  //Block* WithHelper(Expression* obj,
  //                  ZoneStringList* labels,
  //                  bool is_catch_block,
  //                  bool* ok);
  //Statement* ParseWithStatement(ZoneStringList* labels, bool* ok);
  //CaseClause* ParseCaseClause(bool* default_seen_ptr, bool* ok);
  //SwitchStatement* ParseSwitchStatement(ZoneStringList* labels, bool* ok);
  //DoWhileStatement* ParseDoWhileStatement(ZoneStringList* labels, bool* ok);
  //WhileStatement* ParseWhileStatement(ZoneStringList* labels, bool* ok);
  //Statement* ParseForStatement(ZoneStringList* labels, bool* ok);
  //Statement* ParseThrowStatement(bool* ok);
  //Expression* MakeCatchContext(Handle<String> id, VariableProxy* value);
  //TryStatement* ParseTryStatement(bool* ok);
  //DebuggerStatement* ParseDebuggerStatement(bool* ok);

  // Expressions
  Expression* ParseExpression(bool accept_IN, bool* ok);
  
  // --- Parser Support functions 
  ZoneList<Expression*>* ParseArguments(bool* ok);

  // --- AstToken Support 
  
  AstToken::Value NextElement(bool* ok);
  bool ProcessAttributes(bool* ok);
  Token::Value LookupOp(const char* op_str);

 private:
  // Added for attribute processing
  Token::Value attr_op_; // BinOp UOp CountOp CompOp
  Handle<String>  attr_name_; // Id
  Expression* attr_handle_; // Literal
  int attr_pos_; // All elements that support a pos attribute
};

// ----------------------------------------------------------------------------
// Parser functions - from class Parser

FunctionLiteral* AstBuildingParserJsonML::ParseProgram(Handle<String> source,
                                      unibrow::CharacterStream* stream,
                                      bool in_global_context) {
  CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT);

  HistogramTimerScope timer(&Counters::parse);
  Counters::total_parse_size.Increment(source->length());

  // Initialize parser state.
  source->TryFlattenIfNotFlat();
  scanner_.Init(source, stream, 0);
  ASSERT(target_stack_ == NULL);

  // Compute the parsing mode.
  mode_ = FLAG_lazy ? PARSE_LAZILY : PARSE_EAGERLY;
  if (allow_natives_syntax_ || extension_ != NULL) mode_ = PARSE_EAGERLY;

  Scope::Type type =
    in_global_context
      ? Scope::GLOBAL_SCOPE
      : Scope::EVAL_SCOPE;
  Handle<String> no_name = factory()->EmptySymbol();

  FunctionLiteral* result = NULL;
  { Scope* scope = factory()->NewScope(top_scope_, type, inside_with());
    LexicalScope lexical_scope(this, scope);
    TemporaryScope temp_scope(this);
    ZoneListWrapper<Statement> body(16);
    bool ok = true;
    ParseSourceElements(&body, Token::EOS, &ok);
    if (ok) {
      result = NEW(FunctionLiteral(
          no_name,
          top_scope_,
          body.elements(),
          temp_scope.materialized_literal_count(),
          temp_scope.expected_property_count(),
          temp_scope.only_simple_this_property_assignments(),
          temp_scope.this_property_assignments(),
          0,
          0,
          source->length(),
          false));
    } else if (scanner().stack_overflow()) {
      Top::StackOverflow();
    }
  }

  // Make sure the target stack is empty.
  ASSERT(target_stack_ == NULL);

  // If there was a syntax error we have to get rid of the AST
  // and it is not safe to do so before the scope has been deleted.
  if (result == NULL) zone_scope.DeleteOnExit();
  return result;
}


void* AstBuildingParserJsonML::ParseSourceElements(ZoneListWrapper<Statement>* processor,
                                  int end_token,
                                  bool* ok) {
  // SourceElements ::
  //   (Statement)* <end_token>

  // Allocate a target stack to use for this set of source
  // elements. This way, all scripts and functions get their own
  // target stack thus avoiding illegal breaks and continues across
  // functions.
  TargetScope scope(this);

  ASSERT(processor != NULL);
  InitializationBlockFinder block_finder;
  ThisNamedPropertyAssigmentFinder this_property_assignment_finder;
  while (peek() != end_token) {
    Statement* stat = ParseStatement(NULL, CHECK_OK);
    if (stat == NULL || stat->IsEmpty()) continue;
    // We find and mark the initialization blocks on top level code only.
    // This is because the optimization prevents reuse of the map transitions,
    // so it should be used only for code that will only be run once.
    if (top_scope_->is_global_scope()) {
      block_finder.Update(stat);
    }
    // Find and mark all assignments to named properties in this (this.x =)
    if (top_scope_->is_function_scope()) {
      this_property_assignment_finder.Update(top_scope_, stat);
    }
    processor->Add(stat);
  }

  // Propagate the collected information on this property assignments.
  if (top_scope_->is_function_scope()) {
    bool only_simple_this_property_assignments =
        this_property_assignment_finder.only_simple_this_property_assignments();
    if (only_simple_this_property_assignments) {
      temp_scope_->SetThisPropertyAssignmentInfo(
          only_simple_this_property_assignments,
          this_property_assignment_finder.GetThisPropertyAssignments());
    }
  }
  return 0;
}


Statement* AstBuildingParserJsonML::ParseStatement(ZoneStringList* labels, bool* ok) {
  // Statement ::
  //   Block
  //   VariableStatement
  //   EmptyStatement
  //   ExpressionStatement
  //   IfStatement
  //   IterationStatement
  //   ContinueStatement
  //   BreakStatement
  //   ReturnStatement
  //   WithStatement
  //   LabelledStatementExpressionStatement
  //   SwitchStatement
  //   ThrowStatement
  //   TryStatement
  //   DebuggerStatement


  // Keep the source position of the statement
  int statement_pos = scanner().peek_location().beg_pos;
  Statement* stmt = NULL;
  
  // Load the AstTokens - TODO - maybe should be called from the calling func
  AstToken::Initialize();
  
  // HACK for dealing with outer Program element - TODO!
  if (peek() == Token::RBRACK) { 
    Consume(Token::RBRACK);
    if (peek() != Token::EOS) {
      PrintF("========== NOOO! %i", peek()); // TODO  error message
    }
    return NULL;
  }
  // HACK END

  // Must be a "["
  Expect(Token::LBRACK, CHECK_OK);
  
  // Get the 'Element'
  AstToken::Value tok = NextElement(CHECK_OK);
  //PrintF("ParseStatement: tok is %i %s\n", tok, AstToken::String(tok));
  
  // Get the 'Attributes' - if any
  ProcessAttributes(CHECK_OK);
  // N.B The private class vars should not be used in this function because they are reset by recursion.
  // TODO - maybe create a POD class to return the attributes rather than setting instance vars 
  Token::Value attr_op = attr_op_;
  Handle<String> attr_name = attr_name_;
  Expression* attr_handle = attr_handle_;
  //int attr_pos = attr_pos_;
  USE(attr_op);USE(attr_handle);
  
  switch (tok) {
    // HACK for dealing with outer Program element
    case AstToken::kProgram: {
      return NULL;
    } 
    // HACK END
    
    case AstToken::kBlock: {
      //return ParseBlock(labels, ok);
      Block* result = NEW(Block(labels, 16, false));
      Target target(this, result);
      while (peek() != Token::RBRACK) {
        Statement* stat = ParseStatement(NULL, CHECK_OK);
        if (stat && !stat->IsEmpty()) result->AddStatement(stat);
      }
      stmt = result;
      break;
    }

    //case Token::CONST:  // fall through
    case AstToken::kVariable:
      //stmt = ParseVariableStatement(ok);
      break;
    
    case AstToken::kEmptyStatement: {
      stmt = factory()->EmptyStatement();
      break;
    }
    
    case AstToken::kIfStatement: {
      //stmt = ParseIfStatement(labels, ok);
      Expression* condition = ParseExpression(true, CHECK_OK);
      Statement* then_statement = ParseStatement(labels, CHECK_OK);
      Statement* else_statement = ParseStatement(labels, CHECK_OK); // An Empty statement is generated for else
      stmt = NEW(IfStatement(condition, then_statement, else_statement));
      break;
    }
    
    case AstToken::kDoWhileStatement: {
      //stmt = ParseDoWhileStatement(labels, ok);
      DoWhileStatement* loop = NEW(DoWhileStatement(labels));
      Target target(this, loop);

      Statement* body = ParseStatement(NULL, CHECK_OK);

      if (loop != NULL) { //TODO: what's this for
        int position = scanner().location().beg_pos;
        loop->set_condition_position(position);
      }

      Expression* cond = ParseExpression(true, CHECK_OK);

      if (loop != NULL) loop->Initialize(cond, body);
      stmt = loop;
      break;
    }
    
    case AstToken::kWhileStatement: {
      //stmt = ParseWhileStatement(labels, ok);
      WhileStatement* loop = NEW(WhileStatement(labels));
      Target target(this, loop);

      Expression* cond = ParseExpression(true, CHECK_OK);
      Statement* body = ParseStatement(NULL, CHECK_OK);

      if (loop != NULL) loop->Initialize(cond, body);
      stmt = loop;
      break;
    }

    case AstToken::kForStatement:
      //stmt = ParseForStatement(labels, ok);
      break;
    
    case AstToken::kForInStatement:
      //stmt = ParseForStatement(labels, ok);
      break;
    
    case AstToken::kContinueStatement: {
      //stmt = ParseContinueStatement(ok);
      IterationStatement* target = NULL; //TODO: ContinueTargetHelper() - refactored code which returns the target
      stmt = NEW(ContinueStatement(target));
      break;
    }
    
    case AstToken::kBreakStatement: {
      //stmt = ParseBreakStatement(labels, ok);
      BreakableStatement* target = NULL; //TODO: BreakTargetHelper() - refactored code which returns the target
      stmt = NEW(BreakStatement(target));
      break;
    }

    case AstToken::kReturnStatement:
      //stmt = ParseReturnStatement(ok);
      break;

    case AstToken::kWithEnterStatement:
    // kWithExitStatement
      //stmt = ParseWithStatement(labels, ok);
      break;

    case AstToken::kSwitchStatement:
      //stmt = ParseSwitchStatement(labels, ok);
      break;

    case AstToken::kThrow: //TODO: this is defined in the Expression list in ast.h/json-ast-token.h. Why? IsStatement()?
      //stmt = ParseThrowStatement(ok);
      break;

    //case AstToken::kTryCatchStatement:
    //case AstToken::kTryFinallyStatement:
    /*
    //case Token::TRY: {
      // NOTE: It is somewhat complicated to have labels on
      // try-statements. When breaking out of a try-finally statement,
      // one must take great care not to treat it as a
      // fall-through. It is much easier just to wrap the entire
      // try-statement in a statement block and put the labels there
      Block* result = NEW(Block(labels, 1, false));
      Target target(this, result);
      TryStatement* statement = ParseTryStatement(CHECK_OK);
      if (statement) {
        statement->set_statement_pos(statement_pos);
      }
      if (result) result->AddStatement(statement);
      return result;
    }
    */

    //case AstToken::kFunctionLiteral: //TODO: In ExpressionList
      //return ParseFunctionDeclaration(ok);

    //case Token::NATIVE:
      //return ParseNativeDeclaration(ok);Variable

    //case Token::DEBUGGER:
      //stmt = ParseDebuggerStatement(ok);
      //break;
      
    case AstToken::kExpressionStatement: {
      //stmt = ParseExpressionOrLabelledStatement(labels, ok);
      Expression* expr = ParseExpression(true, CHECK_OK);
      stmt = NEW(ExpressionStatement(expr));
      break;
    }

    default:
      stmt = NULL;
      ReportMessage("unexpected_token",
                     Vector<const char*>::empty());
      *ok = false;
      return stmt;
  }

  // Must be a trailing "]"
  Expect(Token::RBRACK, CHECK_OK);

  // Process comma - if any
  if (peek() == Token::COMMA) { Consume(Token::COMMA); }
 
  // Store the source position of the statement. TODO: use attribute 'pos' if set
  if (stmt != NULL) stmt->set_statement_pos(statement_pos);
  return stmt;
}


Expression* AstBuildingParserJsonML::ParseExpression(bool accept_IN, bool* ok) {
  /* Expressions:

  FunctionLiteral
  FunctionBoilerplateLiteral
  Conditional
  Slot
  VariableProxy
  Literal
  RegExpLiteral
  ObjectLiteral
  ArrayLiteral
  CatchExtensionObject
  Assignment
  Throw
  Property
  Call
  CallNew
  CallRuntime
  UnaryOperation
  CountOperation
  BinaryOperation
  CompareOperation
  ThisFunction
  */
  
  // Keep the source position of the statement
  //int expr_pos = scanner().peek_location().beg_pos;
  Expression* expr = NULL;
  
  // Must be a "["
  Expect(Token::LBRACK, CHECK_OK);
  
  // Get the 'Element'
  AstToken::Value tok = NextElement(CHECK_OK);
  //PrintF("ParseExpression: tok is %i %s\n", tok, AstToken::String(tok));
  
  // Get the 'Attributes' - if any
  ProcessAttributes(CHECK_OK);
  // N.B The private class vars should not be used in this function because they are reset by recursion.
  // TODO - maybe create a POD class to return the attributes rather than setting instance vars 
  Token::Value attr_op = attr_op_;
  Handle<String> attr_name = attr_name_;
  Expression* attr_handle = attr_handle_;
  //int attr_pos = attr_pos_;
  
  switch (tok) {

    case AstToken::kFunctionLiteral:
      // FunctionLiteral* Parser::ParseFunctionLiteral
      break;

    case AstToken::kConditional:
      // Expression* ParseConditionalExpression(bool accept_IN, bool* ok);
      break;

    case AstToken::kSlot:
      break;
      
    case AstToken::kVariableProxy:
      // From: ParsePrimaryExpression() - case Token::IDENTIFIER:
      
      //Handle<String> name = ParseIdentifier(CHECK_OK);
      expr = top_scope_->NewUnresolved(attr_name, inside_with());
      break;
      
    case AstToken::kLiteral: {
      //Expression* Parser::ParsePrimaryExpression(bool* ok)
      
      //PrintF("----------Literal Token is %s \n", attr_handle_);
      // TODO: Check attr_handle is set
      expr = attr_handle;
      break;
    }
      
    case AstToken::kRegExpLiteral:
      //Expression* Parser::ParseRegExpLiteral(bool seen_equal, bool* ok)
      break;
      
    case AstToken::kObjectLiteral:
      //Expression* Parser::ParseObjectLiteral(bool* ok)
      break;
      
    case AstToken::kArrayLiteral:
      //Expression* Parser::ParseArrayLiteral(bool* ok)
      break;
      
    case AstToken::kCatchExtensionObject:
      break;
      
    case AstToken::kAssignment: {
      // Expression* ParseAssignmentExpression(bool accept_IN, bool* ok);

      if (!Token::IsAssignmentOp(peek())) {
         //TODO: throw error
      }
      int pos = scanner().location().beg_pos; // TODO: pos of Assign element. should really use the pos attribute
      Expression* left = ParseExpression(true, CHECK_OK);
      Expression* right = ParseExpression(true, CHECK_OK);
      expr = NEW(Assignment(attr_op, left, right, pos));
      break;
    }
      
    case AstToken::kThrow:
      break;
      
    case AstToken::kProperty:
      break;
      
    case AstToken::kCall: {
      // Code From: Parser::ParseLeftHandSideExpression() and 
      int pos = scanner().location().beg_pos;
      Expression* result = ParseExpression(true, CHECK_OK);
      // TODO: test if result is VariableProxy or Property
      
      // TODO: eval code from ParseLeftHandSideExpression()
      
      ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
     
      expr = factory()->NewCall(result, args, pos);
      
      break;
    }
    
    case AstToken::kCallNew:
      //Expression* Parser::ParseNewPrefix(PositionStack* stack, bool* ok)
      //Expression* Parser::ParseMemberWithNewPrefixesExpression
      break;
      
    case AstToken::kCallRuntime:
      break;
      
    case AstToken::kUnaryOperation:
      // Expression* Parser::ParseUnaryExpression(bool* ok) 
      break;
      
    case AstToken::kCountOperation:
      // Expression* Parser::ParsePostfixExpression(bool* ok)
      break;

    case AstToken::kBinaryOperation: {
      // Expression* Parser::ParseBinaryExpression(int prec, bool accept_IN, bool* ok)
      
      // TODO: See the processing of literals in ParseBinary() e.g 2 + 3
      if (!Token::IsBinaryOp(attr_op)) PrintF("+++++++ Must be a binary op\n"); //TODO

      Expression* x = ParseExpression(accept_IN, CHECK_OK);
      Expression* y = ParseExpression(accept_IN, CHECK_OK);
      expr = NEW(BinaryOperation(attr_op, x, y));
      break;
    }

    case AstToken::kCompareOperation: {
      // TODO: See the processing of literals in ParseBinary() e.g 2 + 3
      if (!Token::IsCompareOp(attr_op)) PrintF("+++++++ Must be a compare op\n"); //TODO

      Expression* x = ParseExpression(accept_IN, CHECK_OK);
      Expression* y = ParseExpression(accept_IN, CHECK_OK);
      expr = NEW(CompareOperation(attr_op, x, y));
      break;
    }
    
    case AstToken::kThisFunction:
      break;
      
    default:
      expr = NULL;
      break;
  }

  // Must be a trailing "]"
  Expect(Token::RBRACK, CHECK_OK);
  
  // Process comma - if any
  if (peek() == Token::COMMA) { Consume(Token::COMMA); }
  
  // Store the source position of the statement
  //if (expr != NULL) expr->set_statement_pos(statement_pos);
  return expr;
 
}


// ----------------------------------------------------------------------------
// Parser support functions


ZoneList<Expression*>* AstBuildingParserJsonML::ParseArguments(bool* ok) {
  // Arguments ::
  //   '(' (AssignmentExpression)*[','] ')'

  ZoneListWrapper<Expression> result = factory()->NewList<Expression>(4);
  //Expect(Token::RBRACK, CHECK_OK);
  bool done = (peek() == Token::RBRACK);
  while (!done) {
    Expression* argument = ParseExpression(true, CHECK_OK);
    result.Add(argument);
    done = (peek() == Token::RBRACK);
    //if (!done) Expect(Token::COMMA, CHECK_OK);
  }
  //Expect(Token::RBRACK, CHECK_OK);
  return result.elements();
}


/* TODO - this function is virtual and can be overridden for custom error handling.
   Need to declare in interface is decide to do it.
void AstBuildingParserJsonML::ReportMessageAt(Scanner::Location source_location,
                                        const char* type,
                                        Vector<const char*> args) {
  MessageLocation location(script_,
                           source_location.beg_pos, source_location.end_pos);
  Handle<JSArray> array = Factory::NewJSArray(args.length());
  for (int i = 0; i < args.length(); i++) {
    SetElement(array, i, Factory::NewStringFromUtf8(CStrVector(args[i])));
  }
  Handle<Object> result = Factory::NewSyntaxError(type, array);
  Top::Throw(*result, &location);
}
*/


// ----------------------------------------------------------------------------
// AstToken processing functions


// TODO: Really should be a set to complement the Parser functions e.g NextElement() plus PeekElement() and ConsumeElement()

AstToken::Value AstBuildingParserJsonML::NextElement(bool* ok) {

  Token::Value next = Next();
  const char* s_nextElement = scanner_.literal_string();//scanner_.literal_length());
  AstToken::Value ast_tok = AstToken::Lookup(s_nextElement);
  
  // TODO - should error handling be done here or in calling ParseStatement/Expression
  //if (!(tok_prop == Token::STRING || tok_prop == Token::IDENTIFIER)) {
  if (ast_tok == AstToken::kILLEGAL) {
    //ReportUnexpectedToken(next);
    ReportMessage("unexpected_token", Vector<const char*>(&s_nextElement, 1));USE(next);
    *ok = false;
    return ast_tok;
  }
  
  if (peek() == Token::COMMA) { Consume(Token::COMMA); }
  
  return AstToken::Lookup(s_nextElement);

  //Expect(Token::RBRACK, CHECK_OK);
}


bool AstBuildingParserJsonML::ProcessAttributes(bool* ok) {
  // N.B - for some reason this function must return a value or the compiler complains.
  // Think it's something to do with the call to Next();
  
  // Null the attributes on the class
  attr_op_ = Token::ILLEGAL;
  attr_name_ = NULL;
  attr_handle_ = NULL;
  attr_pos_ = 0;

  if (peek() == Token::LBRACE) {
    Consume(Token::LBRACE);
    while (peek() != Token::RBRACE) {
    
      // --- Process the Attribute name (must be a string or identifier) ---
      
      Token::Value tok_prop = Next();
      if (!(tok_prop == Token::STRING || tok_prop == Token::IDENTIFIER)) {
        ReportUnexpectedToken(tok_prop);
        *ok = false;
        return true;
      }

      // Lookup the AstTokenAttribute enum value using the name string
      const char* s_name = scanner_.literal_string(); // scanner_.literal_length()
      AstTokenAttribute::Value attr = AstTokenAttribute::Lookup(s_name);
      
      // Check token is valid
      if (attr == AstTokenAttribute::kUnknown) { //TODO: kUnknown to kIllegal. More consistent?
        //ReportUnexpectedToken(tok_prop);
        ReportMessage("unexpected_token", Vector<const char*>(&s_name, 1));
        *ok = false;
        return false;
      }

      // --- Process the ":" ---
      Expect(Token::COLON, CHECK_OK);


      // --- Process the Attribute value ---
      
      switch(attr) {
        case AstTokenAttribute::kHandle: {
          // The Literal Handle attribute uses the parsing machinery for Primitives via call to ParsePrimaryExpression() for:
          // true, false, null, undefined, "string", 44 (number),
        
          // Verify is a js 'primitive' type. ParsePrimaryExpression() parses array and objects - so need to test.
          Token::Value tok_value = peek(); // Do not Consume(), Expect() or Next() the token. It needs to be processed by ParsePrimaryExpression().

          if (!(tok_value >= Token::NULL_LITERAL && tok_value <= Token::STRING)) {
            ReportUnexpectedToken(tok_value);
            *ok = false;
            return true;
          }
          attr_handle_ = ParsePrimaryExpression(CHECK_OK);
          break;
        }
      
        case AstTokenAttribute::kName: {
          
          Consume(Token::STRING);
          Handle<String> name =
          factory()->LookupSymbol(scanner_.literal_string(),
                                  scanner_.literal_length());
          attr_name_ = name;
          break;   
        }
        
        case AstTokenAttribute::kPos: {
          Expect(Token::NUMBER, CHECK_OK);
          const char* s_value = scanner_.literal_string();
          attr_pos_ = atoi(s_value); // If not an int the value is set to 0 - which is ok
          //PrintF("--- attr_pos_ : %i \n", attr_pos_);
          break;
        }
      
        case AstTokenAttribute::kOp: {
          // Get the c string - and then lookup the token value
          Expect(Token::STRING, ok);
          const char* s_value = scanner_.literal_string();
          attr_op_ = LookupOp(s_value);
          if (attr_op_ == Token::ILLEGAL) { //TODO: Should really test if is an Operator
            //ReportUnexpectedToken(attr_op_);
            ReportMessage("unexpected_token", Vector<const char*>(&s_value, 1));
            *ok = false;
            return false;
          }
          break;
        }
          
        default: {
          PrintF("-------- Unknow attribute \n"); // TODO - error handling
        }
      
      } // end switch
      
      // Process comma
      if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK);
      
    } // while != RBRACE
    Expect(Token::RBRACE, CHECK_OK);

  } // if
  
  // Consume the comma after {} if exists
  if (peek() == Token::COMMA) { Consume(Token::COMMA); }
  return true; // hardcoded to satisfy compiler.
}


Token::Value AstBuildingParserJsonML::LookupOp(const char* op_str) {
// TODO: This is a HACK. Either:
// - The code from Scanner should be refactored for reuse - if op format is "+".
// - A hashtable - if op format is  "ADD".
    if (op_str == NULL) return Token::ILLEGAL;
    
    int beg = Token::INC;
    int end = Token::IN;
    
    for (int i = beg; i <= end; i++) {
        Token::Value tok = (Token::Value) i;
        const char* str = Token::String(tok); 
        //PrintF("-- LookupOp str is %i %s \n", tok, str);
        if (str != NULL) {
            if (strcmp(op_str, str) == 0) {
                return tok;
            }
        }
    }
    return Token::ILLEGAL;
}


// ----------------------------------------------------------------------------
// The Parser interface.


FunctionLiteral* MakeASTJsonML(bool compile_in_global_context,
                         Handle<Script> script,
                         v8::Extension* extension,
                         ScriptDataImpl* pre_data) {
  bool allow_natives_syntax =
      always_allow_natives_syntax ||
      FLAG_allow_natives_syntax ||
      Bootstrapper::IsActive();
  AstBuildingParserJsonML parser(script, allow_natives_syntax, extension, pre_data);
  
  // throw an error - this func is always called from eval!
  if (pre_data != NULL) { return NULL; } 
  
  Handle<String> source = Handle<String>(String::cast(script->source()));
  SafeStringInputBuffer input(source.location());
  FunctionLiteral* result = parser.ParseProgram(source,
      &input, compile_in_global_context);
  return result;
}

/*
FunctionLiteral* MakeASTJsonML(bool compile_in_global_context,
                         Handle<Script> script,
                         v8::Extension* extension,
                         ScriptDataImpl* pre_data) {PrintF("----- MakeASTJsonML \n");
  bool allow_natives_syntax =
      always_allow_natives_syntax ||
      FLAG_allow_natives_syntax ||
      Bootstrapper::IsActive();
  AstBuildingParserJsonML parser(script, allow_natives_syntax, extension, pre_data);
  if (pre_data != NULL && pre_data->has_error()) {
    Scanner::Location loc = pre_data->MessageLocation();
    const char* message = pre_data->BuildMessage();
    Vector<const char*> args = pre_data->BuildArgs();
    parser.ReportMessageAt(loc, message, args);
    DeleteArray(message);
    for (int i = 0; i < args.length(); i++)
      DeleteArray(args[i]);
    DeleteArray(args.start());
    return NULL;
  }
  Handle<String> source = Handle<String>(String::cast(script->source()));
  SafeStringInputBuffer input(source.location());
  FunctionLiteral* result = parser.ParseProgram(source,
      &input, compile_in_global_context);
  return result;
}
*/
